//
// Created by Japhy on 2017-9-1.
//


#include <stdint.h>

#define LOG_TAG "libpcsc"

#include "alog.h"
#include "usb.h"
#include "ccid.h"
#include <string.h>
#include <stdio.h>

void Init(void) {
    //LOGI(__FUNCTION__);
    usb_init((void *) 0);
}

int SetSlot(int slot) {
    return usb_switch_to_current(slot);
}

int PowerOn(const char *name, unsigned char *atr, size_t *atrlen) {
    uint32_t alen = 0;
    int ret = ccid_connect(atr, &alen);
    (*atrlen) = alen;
    return ret;
}

int Apdu(unsigned char *sApdu, size_t sLen, unsigned char *rApdu, size_t *rlen) {
    uint32_t r_len = 0;
    int ret;

    char asciiApdu[2048] = {0};
    int len = 0;
    for (len = 0; len < sLen; ++len) {
        sprintf(asciiApdu + 2 * len, "%02X", sApdu[len]);
    }
    LOGD("sApdu:%s", asciiApdu);

    *rlen = 0;
    ret = ccid_exchange(sApdu, sLen, rApdu, &r_len);
    if (!ret) {
        *rlen = r_len;

        memset(asciiApdu, 0, sizeof(asciiApdu));
        for (len = 0; len < r_len; ++len) {
            sprintf(asciiApdu + 2 * len, "%02X", rApdu[len]);
        }
        LOGD("rApdu:%s", asciiApdu);
    }
    return ret;
}

static int AscToHex(char c) {
    if ('0' <= c && c <= '9') {
        return c - '0';
    }
    if ('A' <= c && c <= 'F') {
        return c - 'A' + 10;
    }
    if ('a' <= c && c <= 'f') {
        return c - 'a' + 10;
    }
    return -1;
}

static int AscToByte(char h, char l) {
    int bh, bl;
    bh = AscToHex(h);
    bl = AscToHex(l);
    if (bl < 0 || bh < 0) {
        return -1;
    }
    return (bh << 4) | bl;
}

int ApduAscii(const char *sApdu, char *rApdu) {
    int slen = strlen(sApdu);
    unsigned char capdu[2048];
    uint32_t clen;
    unsigned char rapdu[2048];
    uint32_t rlen = 0;
    int i;
    int ret;
    char *r;

    if (slen > 1024) {
        LOGE("sApdu too big: %d", slen);
        return -1;
    }

    if ((slen & 1) != 0) {
        LOGE("sApdu not even");
        return -2;
    }

    for (clen = 0, i = 0; i < slen; i += 2, clen++) {
        int b = AscToByte(sApdu[i], sApdu[i + 1]);
        if (b < 0) {
            LOGE("sApdu invalid: %s", sApdu);
            return -3;
        }
        capdu[clen] = (uint8_t) b;
    }

    ret = ccid_exchange(capdu, clen, rapdu, &rlen);
    if (ret) {
        return ret;
    }

    r = rApdu;
    for (i = 0; i < rlen; i++, r += 2) {
        sprintf(r, "%02X", rapdu[i]);
    }
    *r = 0;
    return ret;
}

void PowerOff() {
    ccid_disconnect();
}

int IsCardPresent(const char *name) {
//    Init();
    if (!usb_is_present()) {
        return 0;
    }
    return ccid_slot_status();
}
